package com.itc.bpm.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.itc.bpm.api.util.collection.CollectionUtils;
import com.itc.bpm.api.util.date.DateUtils;
import com.itc.bpm.bean.*;
import com.itc.bpm.dto.*;
import com.itc.bpm.framework.factory.vo.BpmTaskVo;
import com.itc.bpm.framework.quartz.DynamicQuartzScheduler;
import com.itc.bpm.framework.quartz.TaskJob;
import com.itc.bpm.framework.service.ProcessInstanceService;
import com.itc.bpm.framework.service.TaskExtService;
import com.itc.bpm.framework.websocket.WebSocketServer;
import com.itc.bpm.mapper.BpmProcessTaskExtMapper;
import com.itc.bpm.service.*;
import com.itc.bpm.util.JsonUtils;
import com.itc.bpm.vo.BpmCurrentUserTask;
import com.itc.bpm.vo.BpmTaskRebackVo;
import com.itc.bpm.vo.BpmUserTaskVo;
import com.itc.common.core.constant.Constants;
import com.itc.common.core.domain.R;
import com.itc.common.core.utils.StringUtils;
import com.itc.common.security.utils.SecurityUtils;
import com.itc.system.api.domain.SysUser;
import liquibase.pro.packaged.P;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * 流程任务实例信息
 */
@Service
public class BpmProcessTaskExtServiceImpl extends ServiceImpl<BpmProcessTaskExtMapper, BpmProcessTaskExt> implements BpmProcessTaskExtService {



    @Autowired(required = false)
    BpmProcessTaskExtMapper bpmProcessTaskExtMapper;

    @Autowired
    DynamicQuartzScheduler dynamicQuartzScheduler;

    @Autowired
    TaskExtService taskExtService;

    @Autowired
    WebSocketServer webSocketServer;

    @Autowired
    ProcessInstanceService processInstanceService;

    @Autowired
    BpmTaskFormValueService bpmTaskFormValueService;

    @Autowired
    BpmFormDesignService bpmFormDesignService;

    @Autowired
            @Lazy
    BpmProcessInstanceExtService bpmProcessInstanceExtService;
    @Override
    public BpmProcessTaskExt findTaskByTaskId(String taskId) {
        return this.getOne(new LambdaQueryWrapper<BpmProcessTaskExt>().eq(BpmProcessTaskExt::getTaskId,taskId));
    }

    @Override
    public void cancenProcessTasks(String processInstaneId) {
       List<BpmProcessTaskExt> list =  this.list(new LambdaQueryWrapper<BpmProcessTaskExt>().eq(BpmProcessTaskExt::getProcessInstanceId,processInstaneId).and(wreapper->{
            wreapper.eq(BpmProcessTaskExt::getStatus,0).or().eq(BpmProcessTaskExt::getStatus,1);
        } ));
       for(BpmProcessTaskExt taskExt:list){
           // 去掉定时任务消息提醒
           if(taskExt.getStatus()==0){
               dynamicQuartzScheduler.cancelJob(taskExt.getTaskId(),taskExt.getTaskId());
           }else{
               String jobName = null;
               if(taskExt.getIsCirculate()!=null && taskExt.getIsCirculate()==1){
                   jobName = TaskExtService.CIRCULATE_TASK_JOB_PREFIX+"_"+taskExt.getTaskId();
               }else{
                  jobName = TaskExtService.TASK_JOB_PREFIX+"_"+taskExt.getTaskId();
               }
               dynamicQuartzScheduler.cancelJob(jobName,jobName);
           }
           taskExt.setStatus(3);
           this.updateById(taskExt);
       }
    }

    @Override
    public R<String> claimTask(String taskId) {
        BpmProcessTaskExt bpmProcessTaskExt = bpmProcessTaskExtMapper.selectTaskExtByTaskId(taskId);
        if(bpmProcessTaskExt==null){
            return R.fail("流程任务不存在!");
        }
        Long deptChild = null;
        SysUser sysUser = new SysUser();
        if(SecurityUtils.getLoginUser()!=null && SecurityUtils.getLoginUser().getSysUser()!=null){
            sysUser = SecurityUtils.getLoginUser().getSysUser();
            if(sysUser!=null){
                deptChild = sysUser.getDeptChildId();
            }
        }
        // todo 获取任务信息设置操作人
        taskExtService.claim(taskId, deptChild+"");
        //设置领取时间，领取人
        bpmProcessTaskExt.setApplyTime(new Date());
        bpmProcessTaskExt.setApplyUser(SecurityUtils.getUserId()+"");
        bpmProcessTaskExt.setApplyDeptChild(deptChild+"");
        if(bpmProcessTaskExt.getResponseTime()!=null){
            // 取消待认领任务 循环通知待办
            dynamicQuartzScheduler.cancelJob(taskId,taskId);
        }
        // 循环任务，开启循环任务处理通知
        if(bpmProcessTaskExt.getIsCirculate()!=null && bpmProcessTaskExt.getIsCirculate()==1){
            long fiveMinutesInMillis =  bpmProcessTaskExt.getSpaceTime() * 60 * 1000; // 计算getResponseTime分钟的毫秒数
            Date startTime = new Date(); // 现在的时间
            startTime.setTime(startTime.getTime() + fiveMinutesInMillis); // 五分钟后的时间

            String cron = "0 0/"+bpmProcessTaskExt.getDealTime()+" * * * ?";
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("taskId",taskId);
            jobDataMap.put("noticeType","3");
            jobDataMap.put("taskName",bpmProcessTaskExt.getTaskName());
            jobDataMap.put("candidateUsers",deptChild);
            String jobName = TaskExtService.CIRCULATE_TASK_JOB_PREFIX+"_"+taskId;
            dynamicQuartzScheduler.addJob(jobName,jobName, TaskJob.class,startTime,null,cron,jobDataMap);
        }
        // 开启延迟通知定时任务
        else if(bpmProcessTaskExt.getDealTime()!=null){
            long fiveMinutesInMillis =  bpmProcessTaskExt.getDealTime() * 60 * 1000; // 计算getResponseTime分钟的毫秒数
            Date startTime = new Date(); // 现在的时间
            startTime.setTime(startTime.getTime() + fiveMinutesInMillis); // 五分钟后的时间
            String cron = "0 0/"+bpmProcessTaskExt.getDealTime()+" * * * ?";
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("taskId",taskId);
            jobDataMap.put("noticeType","2");
            jobDataMap.put("taskName",bpmProcessTaskExt.getTaskName());
            jobDataMap.put("candidateUsers",deptChild);
            String jobName = TaskExtService.TASK_JOB_PREFIX+"_"+taskId;
            dynamicQuartzScheduler.addJob(jobName,jobName, TaskJob.class,startTime,null,cron,jobDataMap);
        }
        BpmProcessInstanceExt bpmProcessInstanceExt = bpmProcessInstanceExtService.getProcessInstanceExtByInstanceId(bpmProcessTaskExt.getProcessInstanceId());

        //发送待处理实时消息提醒
        MessageDto messageDto = new MessageDto();
        messageDto.setTaskName(bpmProcessTaskExt.getTaskName());
        messageDto.setTaskId(taskId);
        messageDto.setProcessInstanceId(bpmProcessTaskExt.getProcessInstanceId());
        messageDto.setProcessInstanceName(bpmProcessInstanceExt!=null?bpmProcessInstanceExt.getName():"");
        messageDto.setModelId(bpmProcessInstanceExt!=null?bpmProcessInstanceExt.getBpmModelId()+"":"");

        messageDto.setType(2);
        messageDto.setDate(LocalDateTime.now());
        try {
            webSocketServer.sendInfo(JsonUtils.objectToJson(messageDto),deptChild+"");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        if(bpmProcessTaskExt.getCreateTime()!=null){
           long mins =  getMinutesDifference(bpmProcessTaskExt.getCreateTime(),bpmProcessTaskExt.getApplyTime());
           bpmProcessTaskExt.setRealResponseTime((int) mins);
        }
        bpmProcessTaskExt.setStatus(1);
        this.updateById(bpmProcessTaskExt);
        return R.ok("领取成功！");
    }

    @Override
    public R<BpmViewDto> getTaskListByProcessInstanceId(String processInstanceId) {
        List<HistoricTaskInstance> tasks = taskExtService.findHistoricTaskInstance(processInstanceId);
        List<BpmTaskResDto> taskResDtos = new ArrayList<>();
        BpmTaskResDto dto;
        for(HistoricTaskInstance taskInstance:tasks){
            dto = new BpmTaskResDto();
            dto.setDefinitionKey(taskInstance.getTaskDefinitionKey());
            dto.setTaskId(taskInstance.getId());
            dto.setParentTaskId(taskInstance.getParentTaskId());
            BpmProcessTaskExt taskExt = this.findTaskByTaskId(taskInstance.getId());
            if(taskExt!=null){
                dto.setIsReback(taskExt.getIsReback());
            }
            //已经有结束时间，则已完成，否则进行中
            if(taskInstance.getEndTime()!=null){
                dto.setResult(2);
                dto.setEndTime(taskInstance.getEndTime());
            }else{
                dto.setResult(1);
            }
            dto.setCreateTime(taskInstance.getCreateTime());
            dto.setDurationInMillis(taskInstance.getDurationInMillis());
            taskResDtos.add(dto);
        }
        String xml =  processInstanceService.findProcessXmlData(processInstanceId);
        List<HistoricActivityInstance> activityList =  taskExtService.findHistoricActivityInstance(processInstanceId);
        List<BpmActivityResDto> activityResDtos = new ArrayList<>();
        for(HistoricActivityInstance bean:activityList){
            BpmActivityResDto bpmActivityRespVO = new BpmActivityResDto();

            bpmActivityRespVO.setKey( bean.getActivityId() );
            bpmActivityRespVO.setType( bean.getActivityType() );
            if ( bean.getStartTime() != null ) {
                bpmActivityRespVO.setStartTime(bean.getStartTime() );
            }
            if ( bean.getEndTime() != null ) {
                bpmActivityRespVO.setEndTime( bean.getEndTime());
            }
            bpmActivityRespVO.setTaskId( bean.getTaskId() );
            activityResDtos.add(bpmActivityRespVO);
        }
        BpmViewDto viewDto = new BpmViewDto();
        viewDto.setTasks(taskResDtos);
        viewDto.setXml(xml);
        viewDto.setActivitys(activityResDtos);
        return R.ok(viewDto);
    }

    @Transactional
    @Override
    public R<String> commitTask(BpmUserTaskVo bpmStartVO) {

        BpmProcessTaskExt taskExt = this.bpmProcessTaskExtMapper.selectOne(new LambdaQueryWrapper<BpmProcessTaskExt>().eq(BpmProcessTaskExt::getTaskId,bpmStartVO.getTaskId()).last("limit 1"));
        if(taskExt==null){
            return R.fail("任务不存在，请重新核对提交");
        }
        if(taskExt.getStatus()==3){
            return R.fail("当前任务已取消，不可进行填报！");
        }
        if(taskExt.getStatus()==0){
            return R.fail("当前任务未认领，请认领后进行操作！");
        }
        // 驳回任务操作
        if(taskExt.getIsReback()!=null && taskExt.getIsReback()==1){
            return rebackTaskCommit(bpmStartVO,taskExt);
        }
        // 提交任务
        if(bpmStartVO.getType()==1){
            if(taskExt.getStatus()==2 && (taskExt.getIsRepeatComplete()==null || taskExt.getIsRepeatComplete()!=1)){
                return R.fail("当前任务不可重复提交");
            }
            // 循环终结任务
            if(taskExt.getIsFinishRepeat()!=null && taskExt.getIsFinishRepeat()==1){
                // 终止当前任务 终止当前环节循环任务
                List<BpmProcessTaskExt> circulateTasks = bpmProcessTaskExtMapper.findCirculateTasks(bpmStartVO.getProcessInstanceId());
                for(BpmProcessTaskExt taskExt1:circulateTasks){
                    BpmTaskVo taskVo = new BpmTaskVo();
                    taskVo.setTaskId(taskExt1.getTaskId());
                    taskVo.setInstanceId(taskExt1.getProcessInstanceId());
                    taskVo.setVariables(new HashMap<>());
                    taskVo.setUserId(SecurityUtils.getUserId()+"");
                    taskVo.setComment("完成任务");
                    R result = taskExtService.complete(taskVo);
                    //记录任务状态
                    taskExt1.setStatus(2);
                    taskExt1.setEndTime(new Date());
                    long min = getMinutesDifference(taskExt1.getApplyTime()!=null?taskExt1.getApplyTime():taskExt1.getCreateTime(),taskExt1.getEndTime());
                    // 实际处理时间
                    taskExt1.setRealDealTime((int) min);
                    taskExt1.setCompleteUser(SecurityUtils.getUserId()+"");
                    this.updateById(taskExt1);
                    if(taskExt1.getStatus()==0){
                        dynamicQuartzScheduler.cancelJob(taskExt1.getTaskId(),taskExt1.getTaskId());
                    }else{
                        //完成任务后停掉循环定时任务
                        String jobName = TaskExtService.CIRCULATE_TASK_JOB_PREFIX+"_"+taskExt.getTaskId();
                        dynamicQuartzScheduler.cancelJob(jobName,jobName);
                    }
                }
            }
            // 不是循环任务，完成当前任务
            if(taskExt.getStatus()!=2 && (taskExt.getIsCirculate()==null || taskExt.getIsCirculate()!=1)){
                taskExt.setStatus(2);
                taskExt.setEndTime(new Date());
                long min = getMinutesDifference(taskExt.getApplyTime(),taskExt.getEndTime());
                // 实际处理时间
                taskExt.setRealDealTime((int) min);
                // 封装流程变量信息
                Map<String,Object> varibals=new HashMap<>();;
                if(bpmStartVO.getData()!=null && !bpmStartVO.getData().isEmpty()){
                    Map<String,Object> temMap = JsonUtils.jsonToMap(JsonUtils.objectToJson(bpmStartVO.getData()),Object.class);
                    if(temMap!=null){
                        // 封装特定变量
                        for(String key:temMap.keySet()){
                            varibals.put(key,temMap.get(key));
                        }
                    }
                }
                BpmTaskVo taskVo = new BpmTaskVo();
                taskVo.setTaskId(bpmStartVO.getTaskId());
                taskVo.setInstanceId(bpmStartVO.getProcessInstanceId());
                taskVo.setVariables(varibals);
                taskVo.setUserId(SecurityUtils.getUserId()+"");
                taskVo.setComment("完成任务");
                R result = taskExtService.complete(taskVo);
                if(result.getCode()!= Constants.SUCCESS){
                    return result;
                }

                taskExt.setCompleteUser(SecurityUtils.getUserId()+"");
                //记录任务状态
                this.updateById(taskExt);
                //完成任务后停掉定时任务
                String jobName = TaskExtService.TASK_JOB_PREFIX+"_"+taskExt.getTaskId();
                dynamicQuartzScheduler.cancelJob(jobName,jobName);
            }
        }
        BpmTaskFormValue taskFormValue = new BpmTaskFormValue();
        taskFormValue.setFormCode(bpmStartVO.getFormCode());
        taskFormValue.setTaskId(bpmStartVO.getTaskId());
        taskFormValue.setTaskName(taskExt.getTaskName());
        taskFormValue.setFormId(bpmStartVO.getFormId());
        taskFormValue.setStatus(0);
        taskFormValue.setFromValue(JsonUtils.objectToJson(bpmStartVO.getData()));
        if(bpmStartVO.getServiceId()!=null &&  bpmStartVO.getType()==0){
            taskFormValue.setId(bpmStartVO.getServiceId());
            bpmTaskFormValueService.updateById(taskFormValue);
        }else{
            //历史记录标记为完成状态，新增数据为 正常状态
            if(bpmStartVO.getServiceId()!=null){
                BpmTaskFormValue templValue = new BpmTaskFormValue();
                templValue.setId(bpmStartVO.getServiceId());
                templValue.setStatus(1);
                bpmTaskFormValueService.updateById(templValue);
            }
            bpmTaskFormValueService.save(taskFormValue);
        }
        return R.ok();
    }


    public R<String> rebackTaskCommit(BpmUserTaskVo bpmStartVO,BpmProcessTaskExt taskExt){
        if(bpmStartVO.getServiceId()==null){
            return R.fail("业务数据id不能为空");
        }
        BpmTaskFormValue bpmTaskFormValue = bpmTaskFormValueService.getById(bpmStartVO.getServiceId());
        if(bpmTaskFormValue==null){
            return R.fail("业务id数据不存在，请重新核对");
        }
        bpmTaskFormValue.setFromValue(JsonUtils.objectToJson(bpmStartVO.getData()));
        if(bpmStartVO.getType()==1){
            bpmTaskFormValue.setIsReback(0);
            long num = bpmTaskFormValueService.count(new LambdaQueryWrapper<BpmTaskFormValue>().eq(BpmTaskFormValue::getTaskId,taskExt.getTaskId()).eq(BpmTaskFormValue::getIsReback,1).ne(BpmTaskFormValue::getId,bpmStartVO.getServiceId()));
            if(num==0){
                taskExt.setIsReback(0);
                this.updateById(taskExt);
            }
        }
        if(bpmTaskFormValue.getIsFlagAdd()==null || bpmTaskFormValue.getIsFlagAdd()==0){
            BpmTaskFormValue bpmTaskFormValue1 = new BpmTaskFormValue();
            bpmTaskFormValue1.setId(bpmTaskFormValue.getId());
            bpmTaskFormValue1.setIsReback(2);
            bpmTaskFormValueService.updateById(bpmTaskFormValue1);
            bpmTaskFormValue.setId(null);
            bpmTaskFormValue.setIsFlagAdd(1);
            bpmTaskFormValueService.save(bpmTaskFormValue);
        }else{
            if(bpmStartVO.getType()==1){
                bpmTaskFormValue.setIsFlagAdd(0);
            }
            bpmTaskFormValueService.updateById(bpmTaskFormValue);
        }
        return R.ok();
    }
    @Override
    public R<List<BpmUserTaskDto>> findOurTasks(BpmCurrentUserTask currentUserTask) {
        //查询指定任务
        List<BpmUserTaskDto> list = new ArrayList<>();
        if(StringUtils.isNotEmpty(currentUserTask.getTaskId())){
            BpmProcessTaskExt taskExt = this.findTaskByTaskId(currentUserTask.getTaskId());
            if(taskExt==null){
                return R.fail("查询指定任务不存在！");
            }
            BpmUserTaskDto dto = vailBpmUserTaskDto(taskExt);
            dto  = addParams(dto,taskExt);
            list.add(dto);
        }else{
            Long deptChild;
            SysUser sysUser = new SysUser();
            if(SecurityUtils.getLoginUser()!=null && SecurityUtils.getLoginUser().getSysUser()!=null){
                sysUser = SecurityUtils.getLoginUser().getSysUser();
                if(sysUser!=null){
                    deptChild = sysUser.getDeptChildId();
                } else {
                    deptChild = 0L;
                }
            } else {
                deptChild = 0L;
            }
            List<BpmProcessTaskExt> waitList = this.list(new LambdaQueryWrapper<BpmProcessTaskExt>().eq(BpmProcessTaskExt::getProcessInstanceId,currentUserTask.getProcessInstanceId()).and(w->{
                w.eq(BpmProcessTaskExt::getCandidateUsers, deptChild +"").or().eq(BpmProcessTaskExt::getApplyDeptChild,deptChild);
            }).and(w->{w.lt(BpmProcessTaskExt::getStatus,2).or().eq(BpmProcessTaskExt::getIsReback,1);}) .orderByDesc(BpmProcessTaskExt::getCreateTime));
            if(!CollectionUtil.isEmpty(waitList)){
               for(BpmProcessTaskExt taskExt:waitList){
                   BpmUserTaskDto dto = vailBpmUserTaskDto(taskExt);
                   dto  = addParams(dto,taskExt);
                   list.add(dto);
               }
            }
        }
        return R.ok(list);
    }


    public BpmUserTaskDto addParams(BpmUserTaskDto dto,BpmProcessTaskExt taskExt){
        dto.setResponseTime(taskExt.getResponseTime());
        dto.setApplyTime(taskExt.getApplyTime());
        dto.setApplyUser(taskExt.getApplyUser());
        dto.setIsRepeatComplete(taskExt.getIsRepeatComplete());
        dto.setDealTime(taskExt.getDealTime());
        dto.setRealResponseTime(taskExt.getRealResponseTime());
        dto.setRealDealTime(taskExt.getRealDealTime());
        dto.setIsFinishRepeat(taskExt.getIsFinishRepeat());
        dto.setSpaceTime(taskExt.getSpaceTime());
        dto.setIsCirculate(taskExt.getIsCirculate());
        dto.setCompleteUser(taskExt.getCompleteUser());
        dto.setApplyDeptChild(taskExt.getApplyDeptChild());
        return dto;
    }
    @Override
    public R<List<BpmHistoryTaskDto>> historyTaskRecord(String processInstanceId) {
        List<BpmProcessTaskExt> list = this.list(new LambdaQueryWrapper<BpmProcessTaskExt>().eq(BpmProcessTaskExt::getProcessInstanceId,processInstanceId).orderByAsc(BpmProcessTaskExt::getCreateTime));
        List<BpmHistoryTaskDto> result = new ArrayList<>();
        for(BpmProcessTaskExt taskExt:list){
            BpmHistoryTaskDto dto = new BpmHistoryTaskDto();
            dto.setTaskId(taskExt.getTaskId());
            dto.setTaskName(taskExt.getTaskName());
            dto.setFormCode(taskExt.getFormCode());
            dto.setFormId(taskExt.getFormId()+"");
            dto.setStatus(taskExt.getStatus());
            BpmFormDesign bpmFormDesign = null;
            if(taskExt.getFormId()!=null){
                bpmFormDesign = bpmFormDesignService.getById(taskExt.getFormId());
            }else if(StringUtils.isNotEmpty(taskExt.getFormCode())){
                bpmFormDesign = bpmFormDesignService.findCurrentForm(taskExt.getFormCode());
            }
            if(bpmFormDesign!=null && StringUtils.isNotEmpty(bpmFormDesign.getFields())){
                try {
                    dto.setFiled(JsonUtils.jsonToList(bpmFormDesign.getFields(),FormFiledDto.class));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            List<ObjectNode> nodes = bpmTaskFormValueService.selectTaskHistoryData(taskExt.getTaskId());
            dto.setData(nodes);
            dto = addHisParams(dto,taskExt);
            result.add(dto);
        }
        return R.ok(result);
    }

    public BpmHistoryTaskDto addHisParams(BpmHistoryTaskDto dto,BpmProcessTaskExt taskExt){
        dto.setResponseTime(taskExt.getResponseTime());
        dto.setApplyTime(taskExt.getApplyTime());
        dto.setApplyUser(taskExt.getApplyUser());
        dto.setIsRepeatComplete(taskExt.getIsRepeatComplete());
        dto.setDealTime(taskExt.getDealTime());
        dto.setRealResponseTime(taskExt.getRealResponseTime());
        dto.setRealDealTime(taskExt.getRealDealTime());
        dto.setIsFinishRepeat(taskExt.getIsFinishRepeat());
        dto.setSpaceTime(taskExt.getSpaceTime());
        dto.setIsCirculate(taskExt.getIsCirculate());
        dto.setCompleteUser(taskExt.getCompleteUser());
        dto.setApplyDeptChild(taskExt.getApplyDeptChild());
        return dto;
    }

    @Override
    public R rebackBpmTask(BpmTaskRebackVo rebackVo) {
        BpmProcessTaskExt taskExt = this.findTaskByTaskId(rebackVo.getTaskId());
        if(taskExt==null){
            return R.fail("任务不存在");
        }
        BpmProcessInstanceExt processInstanceExt =  bpmProcessInstanceExtService.getProcessInstanceExtByInstanceId(rebackVo.getProcessInstanceId());
        if(processInstanceExt==null){
            return R.fail("流程实例不存在！");
        }
        if(processInstanceExt.getStatus()==1){
            return R.fail("已经完成的流程不可以操作驳回！");
        }
        BpmTaskFormValue bpmTaskFormValue = bpmTaskFormValueService.getById(rebackVo.getServiceId());
        if(bpmTaskFormValue==null){
            return R.fail("数据记录不存在，请重新核对");
        }
        bpmTaskFormValue.setIsReback(1);
        bpmTaskFormValue.setIsFlagAdd(0);
        bpmTaskFormValue.setRebackDate(new Date());
        bpmTaskFormValue.setRebackReason(rebackVo.getRebackReason());
        bpmTaskFormValue.setRebackUser(SecurityUtils.getUserId()+"");
        bpmTaskFormValueService.updateById(bpmTaskFormValue);
        taskExt.setIsReback(1);
        this.updateById(taskExt);
        BpmProcessInstanceExt bpmProcessInstanceExt = bpmProcessInstanceExtService.getProcessInstanceExtByInstanceId(rebackVo.getProcessInstanceId());
        // todo 席位数据修正
        try {
            //发送待处理实时消息提醒
            MessageDto messageDto = new MessageDto();
            messageDto.setTaskName(taskExt.getTaskName());
            messageDto.setTaskId(taskExt.getTaskId());
            messageDto.setType(4);
            messageDto.setDate(LocalDateTime.now());
            messageDto.setProcessInstanceId(taskExt.getProcessInstanceId());
            messageDto.setProcessInstanceName(bpmProcessInstanceExt!=null?bpmProcessInstanceExt.getName():"");
            messageDto.setModelId(bpmProcessInstanceExt!=null?bpmProcessInstanceExt.getBpmModelId()+"":"");

            // 发送驳回消息
            webSocketServer.sendInfo(JsonUtils.objectToJson(messageDto),taskExt.getApplyDeptChild());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return R.ok();
    }

    public BpmUserTaskDto vailBpmUserTaskDto(BpmProcessTaskExt taskExt){
        BpmFormDesign bpmFormDesign = null;
        if(taskExt.getFormId()!=null){
            bpmFormDesign = bpmFormDesignService.getById(taskExt.getFormId());
        }else if(StringUtils.isNotEmpty(taskExt.getFormCode())){
            bpmFormDesign = bpmFormDesignService.findCurrentForm(taskExt.getFormCode());
        }
        BpmUserTaskDto taskDto = new BpmUserTaskDto();
        taskDto.setFormCode(taskExt.getFormCode());
        taskDto.setTaskId(taskExt.getTaskId());
        taskDto.setTaskName(taskExt.getTaskName());
        taskDto.setStatus(taskExt.getStatus());
        taskDto.setIsReback(taskExt.getIsReback());
        if(bpmFormDesign!=null){
            // 表单约束
            taskDto.setScheme(bpmFormDesign.getFormConf());
            taskDto.setFormId(bpmFormDesign.getId()+"");
            //驳回状态
            BpmTaskFormValue bpmTaskFormValue = null;
            // 任务驳回时，优先处理驳回数据
            if(taskExt.getIsReback()!=null && taskExt.getIsReback()==1){
                bpmTaskFormValue = bpmTaskFormValueService.findRebackLastRecord(taskExt.getTaskId());
            }else{
                bpmTaskFormValue = bpmTaskFormValueService.findLastRecord(taskExt.getTaskId());
            }
            if(bpmTaskFormValue!=null){
                if(StringUtils.isNotEmpty(bpmTaskFormValue.getFromValue())){
                    ObjectNode node = JsonUtils.jsonToObject(bpmTaskFormValue.getFromValue(), ObjectNode.class);
                    // 创建时间封装进入
                    node.put("createTime", bpmTaskFormValue.getCreateTime().toString());
                    node.put("status",bpmTaskFormValue.getStatus());
                    node.put("serviceId",bpmTaskFormValue.getId());
                    node.put("taskId",taskExt.getTaskId());
                    node.put("rebackReason",bpmTaskFormValue.getRebackReason());
                    node.put("rebackDate",bpmTaskFormValue.getRebackDate()+"");
                    node.put("rebackUser",bpmTaskFormValue.getRebackUser());
                    node.put("isReback",bpmTaskFormValue.getIsReback());
                    taskDto.setData(node);
                }
                taskDto.setServiceId(bpmTaskFormValue.getId());
            }
        }
        return taskDto;
    }


    public static long getMinutesDifference(Date date1, Date date2) {
        long diffInMillies = date2.getTime() - date1.getTime();
        return TimeUnit.MINUTES.convert(diffInMillies, TimeUnit.MILLISECONDS);
    }
}
